

#include <string.h>
#include "FreeRTOS.h"
#include "stdlib.h"
#include "gkt_os.h"
#include "g_type.h"
#include "g_1903.h"
#include "g_uart.h"
#include "gkt_defines.h"
#include "gkt_debug.h"
#include "gkt_uart.h"
#include "uart_defines.h"

UART_ATTRS_DEFINE;

#define GKT_CONFIG_OS_ENABLE	1
#define UART_BUFF	1024

#define UART_ST_INIT	(1U << 0)
#define UART_ST_OPENED	(1U << 1)
#define UART_ST_FC_ENABLE	(1U << 2)

#define UART_ST_RX_CONFIG	(1U << 8)
#define UART_ST_RX_BUF_ALLOC	(1U << 9)
#define UART_ST_RX_ENABLED	(1U << 10)
#define UART_ST_RX_BUSY		(1U << 11)
#define UART_ST_RX_BLOCKING	(1U << 12)
#define UART_ST_RX_MASK	(((1U << 8) - 1) << 8)

#define UART_ST_TX_CONFIG	(1U << 16)
#define UART_ST_TX_BUF_ALLOC	(1U << 17)
#define UART_ST_TX_BUSY		(1U << 18)
#define UART_ST_TX_BLOCKING	(1U << 19)
#define UART_ST_TX_MASK	(((1U << 8) - 1) << 16)

typedef struct _gkt_uart_rt_desc {
	uint8_t		*buffer;
	uint32_t	size;
	uint32_t	real_size;
} gkt_uart_rt_desc_s;

typedef struct _uart_rt {
#if defined(GKT_CONFIG_OS_ENABLE) && GKT_CONFIG_OS_ENABLE	
	gkt_semaphore_t	semaphore;
	int result;
#endif
	gkt_uart_rt_desc_s	*desc;
} uart_rt_s;

typedef struct _uart_instance {
	uint32_t	dev_id;
	uint32_t	status;

	gkt_uart_flowctrl_e	flowctrl_type;
	uart_rt_s	rx;
	uart_rt_s	tx;

	/*Non blocking config*/
	gkt_uart_callback callback;
	gkt_uart_callback_attr_t attr;
	uint32_t rx_flag;
	uint32_t alloc_size;
	uint8_t *alloc_addr;
	uint8_t *frame_first_addr;
	uint32_t frame_size;/*0,16,32,64,128Byte*/
} uart_instance_s;

typedef struct _uart {
	int	init;
	uart_instance_s	instances[GKT_UART_MAXNUMS];
} uart_s;
static uart_s s_uart;

static void uart_rx_data_isr(UART_TypeDef *UARTx, uint32_t dev_id, uint32_t status)
{
	uart_instance_s *instance;
	uint8_t temp;
	
	instance = &s_uart.instances[dev_id];
	if (instance->rx_flag == 0) {
		instance->rx_flag = 1;
		instance->frame_first_addr = instance->rx.desc->buffer;
		//gkt_printf("addr=0x%x\n",instance->rx.desc->buffer);
	}
	
	while (G_UART_ReceiveDataLen(UARTx) || G_UART_IsRXFIFONotEmpty(UARTx))	//|| (instance->rx.desc->size > 0)
	{	
		if (instance->rx.desc == NULL) {
			do {
				temp = UARTx->RX_DATA.bit.VAL;
			} while(G_UART_ReceiveDataLen(UARTx));
			gkt_unused(temp);
			// TODO:Disable Rx interrupt, Abnormal interrupt
			instance->status &= ~UART_ST_RX_BUSY;
			G_UART_ITConfig(UARTx, UART_IT_RX, DISABLE);
		}
		else {
			instance->status |= UART_ST_RX_BUSY;
			
			if ((!(instance->status & UART_ST_RX_ENABLED))
				&& (!(instance->status & UART_ST_RX_BLOCKING))) {
				/*Blocking Timeout*/
				instance->status &= ~UART_ST_RX_BUSY;
	            // TODO: Exit loop
            	break;
			}
			if (G_UART_ReceiveDataLen(UARTx) && (instance->rx.desc->size != 0)) 	{
				// TODO:Read the received in the FIFO
				instance->rx.desc->buffer[instance->rx.desc->real_size] = 
														UARTx->RX_DATA.bit.VAL;
				
				//gkt_printf("%x\n",*instance->rx.desc->buffer);
		    	// TODO:Update RX parameters
				instance->rx.desc->size--;
				instance->rx.desc->real_size++;
			}
			
			// TODO:Check if all expected data have been received
	        if (instance->rx.desc->size == 0) {
				if ((instance->callback != NULL) && (instance->alloc_size != 0)) {
					
					if (instance->rx.desc->buffer
						== (instance->alloc_addr + instance->alloc_size)) { 
						//gkt_printf("b=0x%x a=0x%x s=%d\n", instance->rx.desc->buffer,
						//	instance->alloc_addr, instance->alloc_size);
						instance->rx.desc->buffer = instance->alloc_addr;
					}

					if (G_UART_ReceiveDataLen(UARTx) >= 1) {
						if ((G_UART_ReceiveDataLen(UARTx) == 1) && (instance->rx.desc->real_size > 200))
							gkt_delay_us(200);
						//gkt_printf("==%d\n",instance->rx.desc->real_size);
						if (instance->rx.desc->real_size > instance->frame_size) {
							temp = UARTx->RX_DATA.bit.VAL;
						}
						else {
							instance->rx.desc->buffer[instance->rx.desc->real_size] = 
																		UARTx->RX_DATA.bit.VAL;
							instance->rx.desc->real_size++;
						}
					}
					if (G_UART_ReceiveDataLen(UARTx) == 0)  {
						instance->attr.function = GKT_UART_FUNCTION_RX;
						instance->attr.size = instance->rx.desc->real_size;
						instance->attr.buf_offset = instance->frame_first_addr;
						instance->attr.status = GKT_SUCCESS;
						//instance->status &= ~UART_ST_RX_BUSY;
						instance->callback(&instance->attr);
						
						instance->rx.desc->size = 0;
						instance->rx.desc->real_size = 0;
						if (instance->frame_size == 0) {/*No fixed frame mode*/
							if (instance->rx.desc->buffer == instance->alloc_addr + instance->alloc_size)
								instance->rx.desc->buffer = instance->alloc_addr;
						}
						else {/*When data is stored until the last frame*/
							if (instance->rx.desc->buffer >= (instance->alloc_addr + instance->alloc_size - instance->frame_size)) {
								instance->rx.desc->buffer = instance->alloc_addr;
								//gkt_printf("0addr=0x%x\n",instance->rx.desc->buffer);
							}
							else {/*Move the Buffer header to the next frame header*/
								instance->rx.desc->buffer += instance->frame_size;
								//gkt_printf("1addr=0x%x\n",instance->rx.desc->buffer);
							}
						}
						instance->rx_flag = 0;
						instance->status &= ~UART_ST_RX_BUSY;
						break;
					}
					
				}
				else {
					// TODO:Reset RX parameters
		            //instance->rx.desc->buffer = NULL;
		            // TODO:Disable Rx interrupt
					G_UART_ITConfig(UARTx, UART_IT_RX, DISABLE);

					if (instance->rx.semaphore) 
						gkt_semaphore_release(instance->rx.semaphore);
		            // TODO: Exit loop
	          break;
				}
	    	}
		}	
	}
	//gkt_printf("%d\n",instance->rx.desc->real_size);
}

#if 0
void gkt_uart0_irq_handler(void)
{
	uart_instance_s *instance;
	DMA_TypeDef *DMAx  = (DMA_TypeDef *)((uint32_t)MUART0 - sizeof(DMA_TypeDef));
	instance = &s_uart.instances[0];
	
	if (((instance->status & UART_ST_RX_BLOCKING)|| (instance->status & UART_ST_RX_ENABLED))
		&& (G_UART_ReceiveDataLen(MUART0) || G_UART_IsRXFIFONotEmpty(MUART0))) {
		//gkt_printf("Q ");
		uart_rx_data_isr(MUART0, 0, 0);
	}
	else if (instance->status & UART_ST_TX_BLOCKING) {
		G_UART_ITConfig(MUART0, UART_IT_TX, DISABLE);
   		//gkt_printf("\r\n UART0_IRQHandler\n");

		if (DMAx->STATUS.bit.DONE == 1) {
			if (instance->tx.semaphore) 
				gkt_semaphore_release(instance->tx.semaphore);
			//gkt_printf("rel semaphore\n");
			/* Write `1` to clear DMA interrupt */
    		//DMAx->CTRL.bit.CLEAR_INT = 1;
		}
	}	
}

void gkt_uart1_irq_handler(void)
{
	uart_instance_s *instance;
	DMA_TypeDef *DMAx  = (DMA_TypeDef *)((uint32_t)MUART1 - sizeof(DMA_TypeDef));
	instance = &s_uart.instances[1];

	if (((instance->status & UART_ST_RX_BLOCKING)|| (instance->status & UART_ST_RX_ENABLED))
		&& (G_UART_ReceiveDataLen(MUART1) || G_UART_IsRXFIFONotEmpty(MUART1))) {
		uart_rx_data_isr(MUART1, 1, 0);
	}
	else if (instance->status & UART_ST_TX_BLOCKING) {
		
		G_UART_ITConfig(MUART1, UART_IT_TX, DISABLE);
   		gkt_printf("\r\n UART1_IRQHandler\n");

		if (DMAx->STATUS.bit.DONE == 1) {
			if (instance->tx.semaphore) 
				gkt_semaphore_release(instance->tx.semaphore);
			//gkt_printf("rel semaphore\n");
			/* Write `1` to clear DMA interrupt */
    		//DMAx->CTRL.bit.CLEAR_INT = 1;
		}
	}
	
}

void gkt_uart2_irq_handler(void)
{
	uart_instance_s *instance;
	DMA_TypeDef *DMAx  = (DMA_TypeDef *)((uint32_t)MUART2 - sizeof(DMA_TypeDef));
	instance = &s_uart.instances[2];
	
	if (((instance->status & UART_ST_RX_BLOCKING)|| (instance->status & UART_ST_RX_ENABLED))
		&& (G_UART_ReceiveDataLen(MUART2) || G_UART_IsRXFIFONotEmpty(MUART2))) {
		uart_rx_data_isr(MUART2, 2, 0);
	}
	else if (instance->status & UART_ST_TX_BLOCKING) {
		
		G_UART_ITConfig(MUART2, UART_IT_TX, DISABLE);
   		gkt_printf("\r\n UART2_IRQHandler\n");

		if (DMAx->STATUS.bit.DONE == 1) {
			if (instance->tx.semaphore) 
				gkt_semaphore_release(instance->tx.semaphore);
			//gkt_printf("rel semaphore\n");
			/* Write `1` to clear DMA interrupt */
    		//DMAx->CTRL.bit.CLEAR_INT = 1;
		}
	}
}

void gkt_uart3_irq_handler(void)
{
	uart_instance_s *instance;
	DMA_TypeDef *DMAx  = (DMA_TypeDef *)((uint32_t)MUART3 - sizeof(DMA_TypeDef));
	instance = &s_uart.instances[3];
	
	if (((instance->status & UART_ST_RX_BLOCKING)|| (instance->status & UART_ST_RX_ENABLED))
		&& (G_UART_ReceiveDataLen(MUART3) || G_UART_IsRXFIFONotEmpty(MUART3))) {
		uart_rx_data_isr(MUART3, 3, 0);
	}
	else if (instance->status & UART_ST_TX_BLOCKING) {
		
		G_UART_ITConfig(MUART3, UART_IT_TX, DISABLE);
   		gkt_printf("\r\n UART3_IRQHandler\n");

		if (DMAx->STATUS.bit.DONE == 1) {
			if (instance->tx.semaphore) 
				gkt_semaphore_release(instance->tx.semaphore);
			//gkt_printf("rel semaphore\n");
			/* Write `1` to clear DMA interrupt */
    		//DMAx->CTRL.bit.CLEAR_INT = 1;
		}
	}
}
#endif
MUART_Type *uart_get_type(uint32_t dev_id)
{
	if (0 == dev_id)
		return MUART0;
	else if (1 == dev_id)	
		return MUART1;
	else if (2 == dev_id)
		return MUART2;
	else if (3 == dev_id)
		return MUART3;
	else
		return 0;
}
#if 1
void gkt_uart_irq_handler(void)
{
	uint32_t irq_num, dev_id;
	uart_instance_s *instance;
	MUART_Type *uart_type;
	DMA_TypeDef *DMAx;
	
	irq_num = gkt_irq_get_current();
	if ((irq_num >= UART0_IRQn) && (irq_num <= UART3_IRQn)) {
		dev_id = irq_num - UART0_IRQn;
		instance = &s_uart.instances[dev_id];
		uart_type = uart_get_type(dev_id);

		if (instance->status & UART_ST_TX_BUSY) {
	   		//gkt_printf("iq=%d\n",dev_id);
	   		
			DMAx = (DMA_TypeDef *)((uint32_t)uart_type - sizeof(DMA_TypeDef));
			if (DMAx->STATUS.bit.DONE == 1) {				
				instance->status &= ~UART_ST_TX_BUSY;
				G_UART_ITConfig(uart_type, UART_IT_TX, DISABLE);
				
				if (instance->status & UART_ST_TX_BLOCKING) {
					if (instance->tx.semaphore) 
						gkt_semaphore_release(instance->tx.semaphore);
				}
			}
		}

		if ((instance->status & UART_ST_RX_BLOCKING) || (instance->status & UART_ST_RX_ENABLED)) {
		//if (((instance->status & UART_ST_RX_BLOCKING)|| (instance->status & UART_ST_RX_ENABLED))
			//&& (G_UART_ReceiveDataLen(uart_type) || G_UART_IsRXFIFONotEmpty(uart_type))) {
			//gkt_printf("Q ");
			uart_rx_data_isr(uart_type, dev_id, 0);
		}
		
	}		
}
#endif
static int uart_rx_config(uart_instance_s *instance,
				gkt_uart_config_params_s *params)
{
	gkt_gpio_padmux_desc_s c_desc;
	
	if (instance->status & UART_ST_RX_CONFIG) {
		gkt_error("uart_rx_config: uart rx has configed!\n",
				instance->dev_id);
		return GKT_EPERMIT;
	}
	else if (!params) {
		gkt_error("uart_rx_config: params NULL!\n");
		return GKT_EPARAM;
	}

	instance->status &= ~UART_ST_RX_MASK;

	if (!instance->rx.desc) {
		instance->rx.desc = (gkt_uart_rt_desc_s *)malloc(sizeof(gkt_uart_rt_desc_s));
		if (!instance->rx.desc) {
			gkt_error("uart_rx_config: malloc failed\n");
			return GKT_ENOMEMORY;
		}		
	}
	
	if ((params->frame_size > 0) 
		&& (params->buff_size < params->frame_size))
	{
		gkt_error("uart_rx_config: buff_size should >= frame_size\n");
		return GKT_EPARAM;
	}

	instance->rx.desc->size = 0;
	instance->rx.desc->real_size = 0;
	instance->frame_size = params->frame_size;
	if (params->buffer) { 
		instance->rx.desc->buffer = params->buffer;
		instance->alloc_size = params->buff_size;
		instance->alloc_addr = params->buffer;
	}
	else {
		if (params->buff_size != 0) { 
			instance->rx.desc->buffer = (uint8_t *)malloc(params->buff_size);
			if (!instance->rx.desc->buffer) {
				gkt_error("uart_rx_config: alloc buffer failed!\n");
				return GKT_ENOMEMORY;
			}
			instance->status |= UART_ST_RX_BUF_ALLOC;
			instance->alloc_size = params->buff_size;
			instance->alloc_addr = instance->rx.desc->buffer;
		}	
	}

	switch (instance->dev_id) {
		case 0:
			c_desc.pin = GKT_CONFIG_UART0_SIN_PAD;
			c_desc.func = UART0_RXD|PULL_PU;
			//G_GPIO_Config(PRINTRX_PORT, PRINTRX_IO_PIN, UART0_RXD|PULL_PU);
			break;
		case 1:
			c_desc.pin = GKT_CONFIG_UART1_SIN_PAD;
			c_desc.func = UART1_RXD|PULL_PU;
			//G_GPIO_Config(UART1RX_PORT, UART1RX_IO_PIN, UART1_RXD|PULL_PU);
			break;
		case 2:
			c_desc.pin = GKT_CONFIG_UART2_SIN_PAD;
			c_desc.func = UART2_RXD|PULL_PU;
			//G_GPIO_Config(UART2RX_PORT, UART2RX_IO_PIN, UART2_RXD|PULL_PU);
			break;
		case 3:
			c_desc.pin = GKT_CONFIG_UART3_SIN_PAD;
			c_desc.func = UART3_RXD|PULL_PU;
			//G_GPIO_Config(UART3RX_PORT, UART3RX_IO_PIN, UART3_RXD|PULL_PU);
			break;
		default:
			break;
	}
	gkt_gpio_padmux_config(&c_desc);
#if UART_FLOWCTRL_HW_ENABLE
	MUART_Type *uart_type;
	uart_type = uart_get_type(instance->dev_id);
	if (GKT_UART_FLOWCTRL_ENABLE == instance->flowctrl_type) {
		switch (instance->dev_id) {
			case 0:
				c_desc.pin = GKT_CONFIG_UART0_RTS_PAD;
				c_desc.func = UART0_RTS;
				//G_GPIO_Config(PRINTRTS_PORT, PRINTRTS_IO_PIN, UART0_RTS);
				break;
			case 1:
				c_desc.pin = GKT_CONFIG_UART1_RTS_PAD;
				c_desc.func = UART1_RTS;
				//G_GPIO_Config(UART1RTS_PORT, UART1RTS_IO_PIN, UART1_RTS);
				break;
			case 2:
				c_desc.pin = GKT_CONFIG_UART2_RTS_PAD;
				c_desc.func = UART2_RTS;
				//G_GPIO_Config(UART2RTS_PORT, UART2CTS_IO_PIN, UART2_RTS);
				break;
			case 3:
				c_desc.pin = GKT_CONFIG_UART3_RTS_PAD;
				c_desc.func = UART3_RTS;
				//G_GPIO_Config(UART3RTS_PORT, UART3CTS_IO_PIN, UART3_RTS);
				break;
			default:
				break;
		}
	}
	gkt_gpio_padmux_config(&c_desc);
#endif
	instance->status |= UART_ST_RX_CONFIG;

	return GKT_SUCCESS;
}

static void uart_rx_unconfig(uart_instance_s *instance)
{
	//gkt_padmux_release(UART_PADMUX_DESC(instance->dev_id, UART_PAD_SIN));
#if UART_FLOWCTRL_HW_ENABLE
	MUART_Type *uart_type;
	uart_type = uart_get_type(instance->dev_id);
	if (GKT_UART_FLOWCTRL_ENABLE == instance->flowctrl_type) {
		switch (instance->dev_id) {
			case 0:
				G_GPIO_Config(PRINTRTS_PORT, PRINTRTS_IO_PIN, 0xff);
				break;
			case 1:
				G_GPIO_Config(UART1RTS_PORT, UART1RTS_IO_PIN, 0xff);
				break;
			case 2:
				G_GPIO_Config(UART2RTS_PORT, UART2RTS_IO_PIN, 0xff);
				break;
			case 3:
				G_GPIO_Config(UART3RTS_PORT, UART3RTS_IO_PIN, 0xff);
				break;
			default:
				break;
		}
	}
#endif

	if (instance->rx.desc->buffer) {
		if (instance->status & UART_ST_RX_BUF_ALLOC)
			free(instance->rx.desc->buffer);
		instance->rx.desc->buffer = NULL;
		instance->status &= ~UART_ST_RX_BUF_ALLOC;
	}

	instance->status &= ~UART_ST_RX_CONFIG;
}

static int uart_tx_config(uart_instance_s *instance,
				gkt_uart_config_params_s *params)
{
	gkt_gpio_padmux_desc_s c_desc;
	
	if (instance->status & UART_ST_TX_CONFIG) {
		gkt_error("uart_tx_config: uart-%u has configed!\n", instance->dev_id);
		return GKT_EPERMIT;
	}
	else if (!params) {
		gkt_error("uart_tx_config: params NULL!\n");
		return GKT_EPARAM;
	}

	instance->status &= ~UART_ST_TX_MASK;
	switch (instance->dev_id) {
		case 0:
			c_desc.pin = GKT_CONFIG_UART0_SOUT_PAD;
			c_desc.func = UART0_TXD;
			//G_GPIO_Config(PRINTTX_PORT, PRINTTX_IO_PIN, UART0_TXD);
			break;
		case 1:
			c_desc.pin = GKT_CONFIG_UART1_SOUT_PAD;
			c_desc.func = UART1_TXD;
			//G_GPIO_Config(UART1TX_PORT, UART1TX_IO_PIN, UART1_TXD);
			break;
		case 2:
			c_desc.pin = GKT_CONFIG_UART2_SOUT_PAD;
			c_desc.func = UART2_TXD;
			//G_GPIO_Config(UART2TX_PORT, UART2TX_IO_PIN, UART2_TXD);
			break;
		case 3:
			c_desc.pin = GKT_CONFIG_UART3_SOUT_PAD;
			c_desc.func = UART3_TXD;
			//G_GPIO_Config(UART3TX_PORT, UART3TX_IO_PIN, UART3_TXD);
			break;
		default:
			break;
	}
	gkt_gpio_padmux_config(&c_desc);
#if UART_FLOWCTRL_HW_ENABLE
		MUART_Type *uart_type;
		uart_type = uart_get_type(instance->dev_id);
		if (GKT_UART_FLOWCTRL_ENABLE == instance->flowctrl_type) {
			switch (instance->dev_id) {
				case 0:
					c_desc.pin = GKT_CONFIG_UART0_CTS_PAD;
					c_desc.func = UART0_CTS;
					//G_GPIO_Config(PRINTCTS_PORT, PRINTCTS_IO_PIN, UART0_CTS);
					break;
				case 1:
					c_desc.pin = GKT_CONFIG_UART1_CTS_PAD;
					c_desc.func = UART1_CTS;
					//G_GPIO_Config(UART1CTS_PORT, UART1CTS_IO_PIN, UART1_CTS);
					break;
				case 2:
					c_desc.pin = GKT_CONFIG_UART2_CTS_PAD;
					c_desc.func = UART2_CTS;
					//G_GPIO_Config(UART2CTS_PORT, UART2CTS_IO_PIN, UART2_CTS);
					break;
				case 3:
					c_desc.pin = GKT_CONFIG_UART3_CTS_PAD;
					c_desc.func = UART3_CTS;
					//G_GPIO_Config(UART3CTS_PORT, UART3CTS_IO_PIN, UART3_CTS);
					break;
				default:
					break;
			}
		}
		gkt_gpio_padmux_config(&c_desc);
#endif
	instance->status |= UART_ST_TX_CONFIG;

	return GKT_SUCCESS;
}

static void uart_rx_disable(uart_instance_s *instance)
{
	MUART_Type *uart_type;
	
	instance->status &= ~UART_ST_RX_ENABLED;
	uart_type = uart_get_type(instance->dev_id);
	G_UART_ITConfig(uart_type, UART_IT_RX, DISABLE);
}

static void uart_tx_unconfig(uart_instance_s *instance)
{
#if UART_FLOWCTRL_HW_ENABLE
	MUART_Type *uart_type;
	uart_type = uart_get_type(instance->dev_id);
	if (GKT_UART_FLOWCTRL_ENABLE == instance->flowctrl_type) {
		switch (instance->dev_id) {
			case 0:
				G_GPIO_Config(PRINTRTS_PORT, PRINTRTS_IO_PIN, 0xff);
				break;
			case 1:
				G_GPIO_Config(UART1RTS_PORT, UART1RTS_IO_PIN, 0xff);
				break;
			case 2:
				G_GPIO_Config(UART2RTS_PORT, UART2CTS_IO_PIN, 0xff);
				break;
			case 3:
				G_GPIO_Config(UART3RTS_PORT, UART3CTS_IO_PIN, 0xff);
				break;
			default:
				break;
		}
	}
#endif

	if (instance->tx.desc->buffer) {
		if (instance->status & UART_ST_TX_BUF_ALLOC)
			free(instance->tx.desc->buffer);
		instance->tx.desc->buffer = NULL;
		instance->status &= ~UART_ST_TX_BUF_ALLOC;
	}

	instance->status &= ~UART_ST_TX_CONFIG;
}

int gkt_uart_init(void)
{
	uint32_t irq_no;
	uart_instance_s *instance;
	gkt_irq_attr_s irq_attr;
	int dev_id, retval;
	
	if (!s_uart.init) {
		for (dev_id = 0; dev_id < GKT_UART_MAXNUMS; dev_id++) {
			instance = &s_uart.instances[dev_id];

			irq_no = GKT_UART0_IRQ_NO + dev_id; 	
			irq_attr.flags = GKT_IRQ_F_CLEAR | GKT_IRQ_F_ENABLE;
			irq_attr.handler = gkt_uart_irq_handler;
			irq_attr.priority =  GKT_IRQ_PRIORITY(GKT_UART0_IRQ_PRIORITY);
			retval = gkt_irq_setup(irq_no, &irq_attr);
			if (retval) {
				gkt_error("uart_init: gkt_irq_setup err=%d\n", retval);
				continue;
			}	
			instance->status = UART_ST_INIT;
		}
		s_uart.init = 1;
	}

	return GKT_SUCCESS;
}

int gkt_uart_open(uint32_t dev_id, 
			gkt_uart_open_params_s *params)
{
	uart_instance_s *instance;
	MUART_Type *uart_type;
	G_UART_InitTypeDef   UART_InitStruct;
	
	if ((dev_id < GKT_UART_MAXNUMS)
		&& params
		&& (params->data_bits >= GKT_UART_DATABITS_MIN) 
		&& (params->data_bits <= GKT_UART_DATABITS_MAX)
		&& (params->stop_bits < GKT_UART_STOPBITS_MAX)
		&& (params->parity < GKT_UART_PARITY_MAX)
		&& (params->flow_control < GKT_UART_FLOWCTRL_MAX))
	{
		instance = &s_uart.instances[dev_id];
		//gkt_printf("open instance=0x%x\n", &s_uart.instances[dev_id]);
		instance->dev_id = dev_id;
		uart_type = uart_get_type(dev_id);
		if (!(instance->status & UART_ST_INIT)) {
			gkt_error("uart_open: uart-%u not init!\n", dev_id);
			return GKT_ENOTINIT;
		}

		if (instance->status & UART_ST_OPENED) {
			gkt_error("uart_open: uart-%u is already opened!\n", dev_id);
			return GKT_EPERMIT;
		}
		instance->flowctrl_type = params->flow_control;
		if (instance->flowctrl_type)
			G_UART_AutoFlowCtrlCmd(uart_type, ENABLE);
		if (params->data_bits == 8)
			UART_InitStruct.DataBits  = GKT_UART_DATABITS_8B;
		else
			UART_InitStruct.DataBits  = GKT_UART_DATABITS_9B;
	    UART_InitStruct.BaudRate  = params->baud_rate;
	    UART_InitStruct.StopBits  = params->stop_bits;//STOPBITS_1
	    UART_InitStruct.Parity    = params->parity;
	    UART_InitStruct.FlowCtrl  = params->flow_control;
	    UART_InitStruct.RxMode    = MODE_RX_ENABLE;
	    UART_InitStruct.SmartCard = SMARTCARD_DISABLE;
	    UART_InitStruct.CommMode  = MODE_DUPLEX;

		G_UART_Init(uart_type, &UART_InitStruct);
		instance->status |= UART_ST_OPENED;

		gkt_irq_clear_pending(GKT_UART0_IRQ_NO + dev_id);
		gkt_irq_enable(GKT_UART0_IRQ_NO + dev_id);
		
		return GKT_SUCCESS;
	}

	return GKT_EPARAM;
}

/* ------------------------------------------------------- 
** Function:		gkt_uart_close	
** Description:		Close Rx / TX and corresponding padmax
** Input:			
** Output:			
** Return:			
** Others:			
** -------------------------------------------------------*/ 
void gkt_uart_close(uint32_t dev_id)
{
	uart_instance_s *instance;
	
	if (dev_id < GKT_UART_MAXNUMS) {
		instance = &s_uart.instances[dev_id];
		if (instance->status & UART_ST_OPENED) {
			instance->status &= ~UART_ST_OPENED;

			/* config & disable clock */
			//gkt_clkrst_disable_clock(UART_CLKRST_DESC(dev_id));
			/* clear & disable interrupt */
			//NVIC_ClearPendingIRQ((IRQn_Type)(UART0_IRQn+dev_id));
			//NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn+dev_id));
			gkt_irq_clear_pending(GKT_UART0_IRQ_NO + dev_id);
			gkt_irq_disable(GKT_UART0_IRQ_NO + dev_id);
			
			if (instance->status & UART_ST_RX_CONFIG) {
				if (instance->status & UART_ST_RX_ENABLED)
					uart_rx_disable(instance);
				uart_rx_unconfig(instance);
			}

			if (instance->status & UART_ST_TX_CONFIG) {
				uart_tx_unconfig(instance);
			}
		}
	}
}

void gkt_uart_register_callback(uint32_t dev_id,
									gkt_uart_callback callback)
{
	uart_instance_s *instance;

	if (dev_id < GKT_UART_MAXNUMS) {
		instance = &s_uart.instances[dev_id];
		instance->callback = callback;
	}
}

/* ------------------------------------------------------- 
** Function:		gkt_uart_config	
** Description:		
** Input:	func:	TX / RX separate configuration or 
**					configuration together.
**			buffer:	Non blocking setting.
**					(Blocking call configuration is NULL)
**			buff_size: Non blocking buffer size.
**					(Blocking call configuration is 0)
**			callback:Non blocking callback.
**					(blocking call set null).
**			frame_size: 0/16/32/64/128 Byte(Non blocking use)
** Output:			
** Return:			
** Others:			
** -------------------------------------------------------*/ 
int gkt_uart_config(uint32_t dev_id, 
			gkt_uart_function_e func,
			gkt_uart_config_params_s *params)
{
	int retval=0;
	uart_instance_s *instance;
	
	if ((dev_id < GKT_UART_MAXNUMS) 
		&& (func < GKT_UART_FUNCTION_MAX)) 
	{
		instance = &s_uart.instances[dev_id];
		if (!(instance->status & UART_ST_OPENED)) {
			gkt_error("gkt_uart_config: uart-%u not open!\n", dev_id);
			return GKT_ENOTOPEN;
		}

		instance->callback = params->callback;
		
		if (GKT_UART_FUNCTION_RX == func)
			retval = uart_rx_config(instance, params);
		else if (GKT_UART_FUNCTION_TX == func)
			retval = uart_tx_config(instance, params);
		else {
			retval = uart_rx_config(instance, params);
			if (retval == GKT_SUCCESS) {
				retval = uart_tx_config(instance, params);
			}
		}
	}
	else
		retval = GKT_EPARAM;

	return retval;
}

/* ------------------------------------------------------- 
** Function:		gkt_uart_config	
** Description:		Non blocking RX call, blocking without call
**				Only one non blocking and non blocking RX can be selected
** Input:			
** Output:			
** Return:			
** Others:			
** -------------------------------------------------------*/ 
int gkt_uart_rx_enable(uint32_t dev_id)
{
	int retval=0;

	uart_instance_s *instance;
	MUART_Type *uart_type;
	
	if (dev_id < GKT_UART_MAXNUMS) {
		instance = &s_uart.instances[dev_id];
		uart_type = uart_get_type(dev_id);
		if (!(instance->status & UART_ST_OPENED)) {
			gkt_error("uart_rx_enable: uart-%u not open!\n", dev_id);
			return GKT_ENOTOPEN;
		}
		else if (!(instance->status & UART_ST_RX_CONFIG)) {
			gkt_error("uart_rx_enable: uart-%u rx not config!\n", dev_id);
			return GKT_ENOTCONFIG;
		}
		else if (instance->status & UART_ST_RX_BLOCKING) {
			gkt_error("uart_rx_enable: uart-%u rx blocking mode!\n", dev_id);
			return GKT_EBUSY;
		}
		
		if (!(instance->status & UART_ST_RX_ENABLED)) {
			instance->status |= UART_ST_RX_ENABLED;
			//NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn+dev_id));
	        //NVIC_SetPriority((IRQn_Type)(UART0_IRQn+dev_id), 1);
			
			// TODO:Start data transaction
			G_UART_ITConfig(uart_type, UART_IT_RX, ENABLE);
	   		G_UART_SetRxITNum(uart_type, 0xff);
			G_UART_SetITTimeout(uart_type, 3400);
		}
		else
			retval = GKT_SUCCESS;
	}
	else
		retval = GKT_EPARAM;

	return retval;
}

/* ------------------------------------------------------- 
** Function:		gkt_uart_receive	
** Description:		The timeout setting of 0 is non blocking 
** Input:			to_receive_size:Number of bytes to receive
** Output:			received_size:Bytes actually received
** Return:			
** Others:			
** -------------------------------------------------------*/ 
int gkt_uart_receive(uint32_t dev_id, void *buffer, 
			uint32_t to_receive_size, uint32_t timeout, 
			uint32_t *received_size)
{
	int retval=GKT_SUCCESS;
	uart_instance_s *instance;
	MUART_Type *uart_type;

	//gkt_printf("uart receive\n");
	if ((dev_id < GKT_UART_MAXNUMS) 
		&& to_receive_size
		&& buffer && received_size)
	{
		instance = &s_uart.instances[dev_id];
		uart_type = uart_get_type(dev_id);
		DMA_TypeDef *DMAx  = (DMA_TypeDef *)((uint32_t)uart_type - sizeof(DMA_TypeDef));
		
		if (!(instance->status & UART_ST_RX_CONFIG)) {
			gkt_error("uart_receive: uart-%u rx not config!\n", dev_id);
			return GKT_ENOTCONFIG;
		}
		
		if (instance->status & UART_ST_RX_ENABLED) {
			gkt_error("uart_receive: Non blocking receive status\n", dev_id);
			return GKT_EBUSY;
		}
			
		if (timeout) {
			if (!instance->rx.semaphore) {
				instance->rx.semaphore = gkt_semaphore_create(1, 0);
				if (!instance->rx.semaphore) {
					gkt_error("gkt_uart_receive: create device rx sem failed for uart-%d\n", dev_id);
					return GKT_ECREATE;
				}
			}
		}
		else {
			gkt_error("gkt_uart_receive: no block err uart-%d timeout=0\n", dev_id);
			return GKT_EPARAM;
		}

		if (!instance->rx.desc) {
			instance->rx.desc = (gkt_uart_rt_desc_s *)malloc(sizeof(gkt_uart_rt_desc_s));
			if (!instance->rx.desc) {
				gkt_error("gkt_uart_receive: malloc failed uart-%d\n", dev_id);
				return GKT_ENOMEMORY;
			}		
		}
		
		if (timeout) {
			while (GKT_SUCCESS == gkt_semaphore_acquire(instance->rx.semaphore, 0));
			instance->status |= UART_ST_RX_BLOCKING;
		}
		// TODO:Prepare RX parameters
		instance->rx.desc->size = to_receive_size;
		instance->rx.desc->buffer = buffer;
		instance->rx.desc->real_size = 0;

		_ASSERT(IS_UART(uart_type));
    	_ASSERT(NULL != instance->rx.desc->buffer);
    	_ASSERT(instance->rx.desc->size < 0xfffff);

     	//NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn+dev_id));
        //NVIC_SetPriority((IRQn_Type)(UART0_IRQn+dev_id), 1);
		
		// TODO:Start data transaction
		G_UART_ITConfig(uart_type, UART_IT_RX, ENABLE);
   		G_UART_SetRxITNum(uart_type, 0xff);
        G_UART_SetITTimeout(uart_type, 100);

		if (timeout) {
			retval = gkt_semaphore_acquire(instance->rx.semaphore, timeout);
			instance->status &= ~UART_ST_RX_BLOCKING;
			*received_size = instance->rx.desc->real_size;
			if (GKT_SUCCESS != retval)  {
				uint8_t temp;  
				while (G_UART_IsRXFIFONotEmpty(uart_type)) {
					temp = uart_type->RX_DATA.bit.VAL;
				}
				gkt_unused(temp);	
				retval = GKT_ETIMEOUT;
			}
		}
		else
			*received_size = instance->rx.desc->real_size;
		DMAx->CTRL.bit.CLEAR_INT = 1;
		G_UART_ITConfig(uart_type, UART_IT_RX, DISABLE);
		
		return retval;
	}

	return GKT_EPARAM;
}

int gkt_uart_send(uint32_t dev_id, const void *data,
			uint32_t size, uint32_t timeout)
{
	uart_instance_s *instance;
	MUART_Type *uart_type;
	int retval=GKT_SUCCESS;

	if ((dev_id < GKT_UART_MAXNUMS) && data && (size > 0)) {
		instance = &s_uart.instances[dev_id];
		
		if (!(instance->status & UART_ST_OPENED)) {
			gkt_error("gkt_uart_send: uart-%u not open!\n", dev_id);
			return GKT_ENOTOPEN;
		}
		else if (!(instance->status & UART_ST_TX_CONFIG)) {
			gkt_error("gkt_uart_send: uart-%u not config!\n", dev_id);
			return GKT_ENOTCONFIG;
		}
		
		if (instance->status & UART_ST_TX_BLOCKING) {
			gkt_error("gkt_uart_send: blocking id=%d\n", dev_id);
			return GKT_EBUSY;
		}

		if (timeout) {
			if (!instance->tx.semaphore) {
				instance->tx.semaphore = gkt_semaphore_create(1, 0);
				if (!instance->tx.semaphore) {
					gkt_error("gkt_uart_send: create device tx sem failed for uart-%d\n", dev_id);
					return GKT_ECREATE;
				}
			}
		}
		if (!instance->tx.desc) {
			instance->tx.desc = (gkt_uart_rt_desc_s *)malloc(sizeof(gkt_uart_rt_desc_s));
			if (!instance->tx.desc) {
				gkt_error("gkt_uart_send: malloc failed uart-%d\n", dev_id);
				return GKT_ENOMEMORY;
			}		
		}

		if (timeout) {
			while (GKT_SUCCESS == gkt_semaphore_acquire(instance->tx.semaphore, 0));
			instance->status |= UART_ST_TX_BLOCKING;
			instance->tx.desc->buffer = (uint8_t *)data;
		}
		else {
			if (instance->callback == NULL) {
				gkt_error("gkt_uart_send: no callback err uart-%d\n", dev_id);
				return GKT_EPARAM;
			}
			instance->tx.desc->buffer = (uint8_t *)malloc(size);
			if (!instance->tx.desc->buffer) {
				gkt_error("gkt_uart_send: malloc buf failed uart-%d\n", dev_id);
				return GKT_ENOMEMORY;
			}
			memcpy(instance->tx.desc->buffer, (uint8_t *)data, size);
		}
		// TODO:Prepare TX parameters
		instance->tx.desc->size = size;
		instance->tx.desc->real_size = 0;
		uart_type = uart_get_type(dev_id);
		
		/* Enable Tx interrupt */
		instance->status |= UART_ST_TX_BUSY;
		G_UART_ITConfig(uart_type, UART_IT_TX, ENABLE);
		G_UART_SendBuf(uart_type, instance->tx.desc->buffer, instance->tx.desc->size);

		if (timeout) {
			retval = gkt_semaphore_acquire(instance->tx.semaphore, timeout);
			instance->status &= ~UART_ST_TX_BLOCKING;
		}
		else {
			free(instance->tx.desc->buffer);
		}
		//if (instance->status & UART_ST_RX_ENABLED) {
			/* enable rx interrupt */
		//	uartreg_enable_rx_int(UART_BASEADDR(dev_id));
		//}
		
		return retval;
	}
	return GKT_EPARAM;
}

int gkt_uart_flow_control(uint32_t dev_id, int enable)
{
	uart_instance_s *instance;
	MUART_Type *uart_type;
	
	if (dev_id < GKT_UART_MAXNUMS) {
		instance = &s_uart.instances[dev_id];
		uart_type = uart_get_type(dev_id);
		if (!(instance->status & UART_ST_OPENED)) {
			gkt_error("gkt_uart_flow_control: uart-%u not open!\n", dev_id);
			return GKT_ENOTOPEN;
		}

		if (instance->flowctrl_type != GKT_UART_FLOWCTRL_NONE) {
			if (enable) {
				G_UART_AutoFlowCtrlCmd(uart_type, ENABLE);
				instance->status |= UART_ST_FC_ENABLE;
			}
			else {
				// First check if no transmission is ongoing
		        if (instance->status & UART_ST_TX_BLOCKING) 
		            return GKT_EBUSY;
		        
				G_UART_AutoFlowCtrlCmd(uart_type, DISABLE);
				instance->status &= ~UART_ST_FC_ENABLE;
			}

			return GKT_SUCCESS;
		}
	}

	return GKT_EPARAM;
}

int gkt_uart_flush(uint32_t dev_id)
{
	uart_instance_s *instance;
	MUART_Type *uart_type;
	uint8_t temp;

	if (dev_id < GKT_UART_MAXNUMS) {
		instance = &s_uart.instances[dev_id];
		uart_type = uart_get_type(dev_id);
		if (!(instance->status & UART_ST_OPENED)) {
			gkt_error("gkt_uart_flush: uart-%u not open!\n", dev_id);
			return GKT_ENOTOPEN;
		}
		
		DMA_TypeDef *DMAx = (DMA_TypeDef *)((uint32_t)uart_type - sizeof(DMA_TypeDef));
		while (G_UART_IsRXFIFONotEmpty(uart_type)) {
			temp = uart_type->RX_DATA.bit.VAL;
			gkt_unused(temp);
		}
		DMAx->CTRL.bit.CLEAR_INT = 1;
	}
	
	return GKT_SUCCESS;
	
}

int gkt_uart_putc(uint32_t dev_id, char ch)
{
	uart_instance_s *instance;
	MUART_Type *uart_type;

	if (dev_id < GKT_UART_MAXNUMS) {
		instance = &s_uart.instances[dev_id];
		if (!(instance->status & UART_ST_OPENED)) {
			return GKT_ENOTOPEN;
		}
		else if (!(instance->status & UART_ST_TX_CONFIG)) {
			gkt_error("gkt_uart_putc: uart-%u not config!\n", dev_id);
			return GKT_ENOTCONFIG;
		}
		
		uart_type = uart_get_type(dev_id);
		//if (instance->status & UART_ST_RX_ENABLED) {
		//	while (instance->status & UART_ST_RX_BUSY)
		//		gkt_thread_sleep(10);
		//	uartreg_disable_rx_int(base_addr);
		//}
		if (ch == '\n') {
			G_UART_SendData(uart_type, '\r');
		}
		G_UART_SendData(uart_type, ch);

		//if (instance->status & UART_ST_RX_ENABLED)
		//	uartreg_enable_rx_int(base_addr);
		
		return GKT_SUCCESS;
	}

	return GKT_EPARAM;
}

int gkt_uart_puts(uint32_t dev_id, const char *string)
{
	int retval=GKT_SUCCESS;
	uart_instance_s *instance;
	MUART_Type *uart_type;
	
	if ((dev_id < GKT_UART_MAXNUMS) && string) {
		instance = &s_uart.instances[dev_id];
		if (!(instance->status & UART_ST_OPENED)) {
			return GKT_ENOTOPEN;
		}
		else if (!(instance->status & UART_ST_TX_CONFIG)) {
			gkt_error("gkt_uart_puts: uart-%u not config!\n", dev_id);
			return GKT_ENOTCONFIG;
		}
		
		if (!instance->tx.semaphore) {
			instance->tx.semaphore = gkt_semaphore_create(1, 0);
			if (!instance->tx.semaphore) {
				gkt_error("gkt_uart_puts: create device tx sem failed for uart-%d\n", dev_id);
				return GKT_ECREATE;
			}
		}

		while (GKT_SUCCESS == gkt_semaphore_acquire(instance->tx.semaphore, 0));
		
		// Prepare TX parameters
		instance->tx.desc->buffer = (uint8_t *)string;
		instance->tx.desc->size = strlen(string);
		instance->tx.desc->real_size = 0;

		/* start data transaction
		 * first isr execution is done without interrupt generation to reduce
		 * interrupt load
		 */
		if (instance->status & UART_ST_RX_ENABLED) {
			while (instance->status & UART_ST_RX_BUSY)
				gkt_thread_sleep(10);
			/* disable rx interrupt */
			//uartreg_disable_rx_int(UART_BASEADDR(dev_id));
		}

		uart_type = uart_get_type(dev_id);
		/* Enable Tx interrupt */
		//NVIC_EnableIRQ(UART0_IRQn);
     	//NVIC_SetPriority(UART0_IRQn, 1);
		
		G_UART_ITConfig(uart_type, UART_IT_TX, ENABLE);
		
		_ASSERT(IS_UART(uart_type));
	    _ASSERT(NULL != instance->tx.desc->buffer);
	    _ASSERT(instance->tx.desc->size < 0xfffff);

	    DMA_TypeDef *DMAx                = (DMA_TypeDef *)((uint32_t)MUART0 - sizeof(DMA_TypeDef));
	    DMAx->SRC_ADDR.reg               = (uint32_t)instance->tx.desc->buffer;
	    DMAx->LEN_LOW.bit.TX_LEN_L       = instance->tx.desc->size & 0xffff;
	    DMAx->CTRL.bit.TX_LEN_H          = instance->tx.desc->size >> 16;
	    DMAx->CTRL.bit.START             = 1;

		//delay_ms(20);
		retval = gkt_semaphore_acquire(instance->tx.semaphore, GKT_INFINITE);
		if (GKT_SUCCESS != retval)  
			retval = GKT_ETIMEOUT;

		//if (instance->status & UART_ST_RX_ENABLED) {
			/* enable rx interrupt */
		//	uartreg_enable_rx_int(UART_BASEADDR(dev_id));
		//}
		
		return retval;
	}

	return GKT_EPARAM;
}

GKT_DEVICE_DESC_DEFINE(uart, BASE);

